<script setup lang="ts">
import { reactive, ref, h, computed } from "vue"
import { ElForm, ElTabs, ElTabPane, ElFormItem, ElInput, ElButton, ElDivider, ElSelectV2, ElMessage, ElCheckboxGroup, ElCheckbox, ElRadioGroup, ElRadio, ElTag } from "element-plus"
import PropertiesItem from "../../components/properties-items/index.vue"
import { IPackNifi } from "src/inter";
import { diff } from "../../util"
import PropertiesAdd from "../../components/properties-items/add.vue";
import {BoxCopy} from "ui-base"
import {DEFAULT_STATUS_NAME} from "../metadata"
import {t} from "../../i18n/index"

const { cell, nifi, disabled = false } = defineProps<IPackNifi.CellProps>();
//
const isDisabled = computed(() => nifi.graph.mode.value == 'prod' || cell.prop('status') === DEFAULT_STATUS_NAME.Running.en || disabled);
// 默认的调度策略选项
const DEFAULT_SCHEDU_STRTEGY = [{ value: 'TIMER_DRIVEN', label: "定时器驱动" }, { value: 'CRON_DRIVEN', label: "基于CRON表达式的驱动" }];
// 默认的执行选项
const DEFAULT_EXECUT_NODE = [{ value: 'ALL', label: "所有节点" }, { value: 'PRIMARY', label: "主节点" }]
//
const id = cell.id;

const cd = nifi.cells.get(cell) || {};
const cdata = cd.component || {};
const type = cdata.type;
const supportsSensitiveDynamicProperties = cdata.supportsSensitiveDynamicProperties;
const relationships:any[] = cdata.relationships || [];
const config = cdata.config || {}
const revision = cd.revision;
// const defaultSchedulingPeriod = config.defaultSchedulingPeriod || {};
// const defaultConcurrentTasks = config.defaultConcurrentTasks || {}
//
const { name } = cdata;
const {
    comments,
    properties,
    descriptors,
    schedulingStrategy,
    schedulingPeriod,
    concurrentlySchedulableTaskCount,
    executionNode,
    autoTerminatedRelationships = relationships.filter(d => d.autoTerminate).map(d => d.name),
    retriedRelationships = relationships.filter(d => d.retry).map(d => d.name),
    retryCount,
    backoffMechanism,
    maxBackoffPeriod,
} = config;
//
const { form, includeProps = [], excludeProps = [], beforeOpen, open, beforeClose, beforeSubmit } = nifi.cells.processors.getMetadata(type) || {};

// 打开之前的回调，如果不允许打开表单，表单会直接打开失败！
if (beforeOpen && beforeOpen.call(nifi, cell) === false) {
    nifi.drawer.close();
}

const showNormal = includeProps != undefined && includeProps.length > 0 || form != undefined;

// 构造表单属性
const propertiesNames = Object.keys(descriptors);
// 基础属性
const baseNames = includeProps.filter((k:any) => propertiesNames.includes(k));
// 高级属性
const adavnceNames = propertiesNames.filter(k => !new Array().concat(includeProps, excludeProps).includes(k))
const dynamicNames = reactive<string[]>([])
const dynamicDescriptors:Record<string,any> = {}
// 构造表单数据
const model = reactive({
    properties: { ...properties }, name, comments,
    config: { comments, schedulingStrategy, schedulingPeriod, concurrentlySchedulableTaskCount, executionNode, autoTerminatedRelationships: [...autoTerminatedRelationships], retriedRelationships: [...retriedRelationships], retryCount, backoffMechanism, maxBackoffPeriod }
})
// 
const activeName = ref(showNormal ? 'normal' : adavnceNames.length > 0 ? "advance" : "info")
//
const errorMsg = reactive<{verificationStepName:string,outcome:string,explanation:string}[]>([])

if (open) {
    open.call(nifi, cell);
}
// 刷新参数列表
nifi.Parameters.refreshList();
//
const refreshDescriptor = async (name:string,sensitive = false) => {
    const url = `/nifi-api/processors/${id}/descriptors?propertyName=${name}&sensitive=${sensitive}`;
    try {
        const res = await nifi.api.get(url);
        return res.propertyDescriptor;
    } catch (error) {
        ElMessage.error('获取表单属性信息失败 :: ' + error);
        console.error(error)
        return {};
    }
}
//
const handleStrategyChange = (v: string) => {
    model.config.concurrentlySchedulableTaskCount = '1';
    if (v == 'CRON_DRIVEN') {
        model.config.schedulingPeriod = '* * * * * ?';
    }
    else {
        model.config.schedulingPeriod = '0 sec';
    }
}
// 取消 和 提交
const elFormRef = ref<InstanceType<typeof ElForm>>();

// 对比表单值和原始值的，获取对比之后的属性差集
const diffAttr = () => {
    const sd = { properties: { ...properties }, name, comments, config: { comments, schedulingStrategy, schedulingPeriod, concurrentlySchedulableTaskCount, executionNode, autoTerminatedRelationships, retriedRelationships, retryCount, backoffMechanism, maxBackoffPeriod } }
    // 提取变化值
    const d = diff(model, sd);
    return d;
}

//

const advanceRef = ref();
const addProperties = (propertyName:string,sensitive:boolean) => {
    const url = `/nifi-api/processors/${id}/descriptors?propertyName=${propertyName}&sensitive=${sensitive}`
    return nifi.api.get(url)
}
// 新增属性
const handleAdd = () => {
    console.log(advanceRef.value)
    activeName.value = 'advance';
    //
    nifi.box.dialog((e) => h(PropertiesAdd,{supportsSensitiveDynamicProperties,box:e,add:addProperties,onSubmit:(d) => {
        dynamicDescriptors[d.name] = d;
        dynamicNames.push(d.name);
        setTimeout(() => {
            advanceRef.value?.$el.parentElement?.scrollTo({top:advanceRef.value.$el.offsetHeight + 100,behavior: "smooth"});
        },500)
    }}),{showFooter:false})
}

//
const checkLoading = ref(false)
// 校验属性
const handleCheckAttr = async () => {
    checkLoading.value = true;
    //
    const d = diffAttr();
    try {
        let url = `/nifi-api/processors/${id}/config/analysis`;
        let res = await nifi.api.post(url, d?.properties ? {configurationAnalysis:{componentId: id, properties: d.properties}} : { configurationAnalysis: { componentId: id, properties: {},referencedAttributes:{},supportsVerification:false } });
        //
        url = `/nifi-api/processors/${id}/config/verification-requests`
        //
        res = await nifi.api.post(url, { request: { componentId: id, properties: d?.properties || {}, attributes: {} } })
        //
        url = `/nifi-api/processors/${id}/config/verification-requests/${res.request.requestId}`
        do {
            await new Promise((resolve) => setTimeout(() => resolve(true), 500));
            res = await nifi.api.get(url);
        }
        while (res.request.complete == false)
        res = await nifi.api.delete(url)
        //
        errorMsg.length = 0;
        errorMsg.push(...res.request.results);
    } catch (error) {
        ElMessage.error('校验失败 :: ' + error);
        console.error(error)
    }
    //
    checkLoading.value = false;
}
// 取消
const handleCanel = () => { handleClose(); }
// 提交
const loading = ref(false)
const handleSubmit = async () => {
    loading.value = true;
    // 提交前回调
    if (beforeSubmit) {
        const b = await beforeSubmit.call(nifi, model, elFormRef.value, cell)
        if (b === false) {
            loading.value = false;
            return;
        }
    }
    // 校验
    try {
        await elFormRef.value?.validate();
    } catch (error) {
        ElMessage.warning('表单验证失败，请检查表单值是否符合要求')
        loading.value = false;
        return;
    }
    // 提取变化值
    const d = diffAttr()
    if (d == undefined) {
        ElMessage.info('未检测到表单值变化，无需更新, 关闭表单')
        // console.info('未检测到表单值变化，无需更新 :: ========> ',sd,model)
        handleClose();
        loading.value = false;
        return;
    }
    const data: any = { component: { config: {}, id } ,revision:{...revision,clientId:nifi.flow.clientId}};
    if (d.config) {
        data.component.config = { ...d.config }
    }
    if (d.properties) {
        data.component.config.properties = d.properties;
    }
    if (d.name) {
        data.component.name = d.name;
    }
    if (d.comments) {
        data.component.config.comments = d.comments;
    }
    // 调用接口
    try {
        // 调用接口 设置元素属性
        const res = await nifi.cells.setCell(cell, data);
        // 刷新节点
        nifi.cells.processors.update(res);
        // 关闭面板
        handleClose();
    } catch (error) {
        ElMessage.error('更新节点失败 :: ' + error);
        console.error(error)
    }
    loading.value = false;

}

const handleClose = async () => {
    let b = true;
    if (beforeClose) {
        b = await beforeClose.call(nifi, model, elFormRef.value, cell)
    }
    if (b !== false) {
        nifi.drawer.close();
    }
}




</script>

<template>
    <div class="w-full h-full flex flex-col gap-8px">
        <!-- header -->
        <div class="w-full h-40px flex justify-between items-center gap-16px">
            <div class="flex-1 overflow-hidden flex flex-nowrap gap-8px items-center justify-start">
                <b class="flex-1 truncate ">{{ model.name }}</b>
                <i class="c-#aaa">{{ cell.prop('type')?.split('.').pop() }}</i>
            </div>
            <div v-if="isDisabled" >
                <el-button @click="handleCanel" type="primary" plain>确定</el-button>
            </div>
            <div v-else class="w-240px flex justify-between">
                <el-button type="success" plain title="新增属性" @click="handleAdd">
                    <div class="i-typcn:plus-outline w-1em h-1em "></div>
                </el-button>
                <el-button type="warning" plain title="校验属性" @click="handleCheckAttr" :loading="checkLoading">
                    <div class="i-ic:outline-fact-check w-1em h-1em"></div>
                </el-button>
                <el-button @click="handleCanel" type="default" plain>取消</el-button>
                <el-button @click="handleSubmit" type="primary" :loading="loading">提交</el-button>
            </div>
        </div>
        <!-- error message -->
        <div v-if="errorMsg.length > 0"
            class="max-h-200px overflow-auto w-full flex flex-col gap-8px scroll-thin text-12px lh-1.2em">
            <template v-for="msg in errorMsg">
                <div :class="['p-x-8px p-y-4px b-1px b-solid rd-4px w-full box-border',msg.outcome == 'SUCCESSFUL' ? 'c-#67c23a b-#67c23a bg-#f0f9eb' : 'c-#f56c6c b-#f56c6c bg-#fef0f0']">
                    <div class="flex items-center gap-1em">
                        <i v-if="msg.outcome == 'SUCCESSFUL'" class="c-#67c23a i-mingcute:check-2-line w-1em h-1em"></i>
                        <i v-else class="c-#f56c6c i-icon-park-outline:error w-1em h-1em"></i>
                        <b>{{ msg.verificationStepName }}</b> 
                    </div>
                    
                    <div class="p-l-2em w-full box-border">{{ msg.explanation }}</div>
                </div>
            </template>
        </div>
        <!-- form -->
        <el-form ref="elFormRef" :model="model" :disabled="isDisabled" class="flex-1 overflow-hidden"
            label-width="200px" label-position="left">
            <el-tabs v-model="activeName" class="h-full w-full overflow-hidden">
                <el-tab-pane label="节点信息" name="info" class="p-4px">
                    <el-form-item label="名称" prop="name" required>
                        <el-input v-model="model.name"></el-input></el-form-item>
                    <el-form-item label="描述" prop="comments" >
                        <el-input v-model="model.comments" type="textarea"></el-input></el-form-item>
                    
                        <!-- 额外信息 -->
                        <BoxCopy :text="id"><div class="c-#999 flex p-y-6px m-b-8px rd-4px"><span class="w-200px box-border p-l-6px">ID:</span> {{ id }}</div></BoxCopy>
                        <!-- <BoxCopy :text="type"><div class="c-#999 flex p-y-6 bg-#f8f8f8 rd-4"><span class="w-200 box-border p-l-6">类名:</span> {{ type }}</div></BoxCopy> -->
                </el-tab-pane>

                <el-tab-pane v-if="showNormal" label="常用属性" name="normal">
                    <component v-if="form" :is="form"
                        v-bind:scope="{ model, cell, descriptors, component: cdata, nifi }">
                    </component>
                    <el-divider v-if="form && baseNames.length > 0"></el-divider>
                    <template v-for="k in baseNames" :key="k">
                        <PropertiesItem v-model="model.properties[k]" :prop="['properties',k]" :descriptor="descriptors[k]" :model="model"
                            :nifi="nifi" :refresh="refreshDescriptor"></PropertiesItem>
                    </template>
                </el-tab-pane>

                <el-tab-pane ref="advanceRef"  label="高级属性" name="advance">
                    <template v-for="k in adavnceNames" :key="k">
                        <PropertiesItem v-model="model.properties[k]" :prop="['properties',k]" :descriptor="descriptors[k]" :model="model"
                            :nifi="nifi" :refresh="refreshDescriptor"></PropertiesItem>
                    </template>
                    <!-- 动态新增的属性 -->
                    <template v-for="(k,i) in dynamicNames" :key="k">
                        <PropertiesItem v-model="model.properties[k]" :prop="['properties',k]" :descriptor="dynamicDescriptors[k]" :model="model" :autofocus="i + 1 == dynamicNames.length"
                            :nifi="nifi" :refresh="refreshDescriptor" ></PropertiesItem>
                    </template>
                </el-tab-pane>
                <el-tab-pane label="调度配置" name="scheduler">
                    <el-form-item label="调度策略" :prop="['config', 'schedulingStrategy']">
                        <el-select-v2 v-model="model.config.schedulingStrategy" :options="DEFAULT_SCHEDU_STRTEGY"
                            @change="handleStrategyChange"></el-select-v2>
                    </el-form-item>
                    <el-form-item label="并发任务数" :prop="['config', 'concurrentlySchedulableTaskCount']"
                        :rules="[{ pattern: /^\d+$/, message: '请输入数字' }]">
                        <el-input v-model="model.config.concurrentlySchedulableTaskCount"
                            :disabled="model.config.schedulingStrategy == 'TIMER_DRIVEN'"></el-input>
                    </el-form-item>
                    <el-form-item label="运行计划" :prop="['config', 'schedulingPeriod']">
                        <el-input v-model="model.config.schedulingPeriod"></el-input>
                    </el-form-item>
                    <el-form-item label="执行范围" :prop="['config', 'executionNode']">
                        <el-select-v2 v-model="model.config.executionNode"
                            :options="DEFAULT_EXECUT_NODE"></el-select-v2>
                    </el-form-item>
                </el-tab-pane>
                <el-tab-pane label="关系配置" name="relation">
                    <el-form-item label="需要终止的状态">
                        <el-checkbox-group v-model="model.config.autoTerminatedRelationships">
                            <el-checkbox v-for="item in relationships" :label="item.name"
                                :value="item.name"></el-checkbox>
                        </el-checkbox-group>
                    </el-form-item>
                    <el-form-item label="需要重试的状态">
                        <el-checkbox-group v-model="model.config.retriedRelationships">
                            <el-checkbox v-for="item in relationships" :label="item.name"
                                :value="item.name"></el-checkbox>
                        </el-checkbox-group>
                    </el-form-item>
                    <fieldset v-if="model.config.retriedRelationships.length > 0"
                        class="p-12px p-t-2px rd-4px b-gray-300 b-solid">
                        <legend class="c-#999">重试参数配置</legend>
                        <el-form-item label="重试尝试次数" prop="config.retryCount"
                            :rules="[{ pattern: /^\d+$/, message: '请输入数字' }]">
                            <el-input v-model="model.config.retryCount"></el-input>
                        </el-form-item>
                        <el-form-item label="重试退避策略" prop="config.backoffMechanism">
                            <el-radio-group v-model="model.config.backoffMechanism">
                                <el-radio value="YIELD_PROCESSOR">暂停执行</el-radio>
                                <el-radio value="PENALIZE_FLOWFILE">惩罚</el-radio>
                            </el-radio-group>
                        </el-form-item>
                        <el-form-item label="重试最大退避时间" prop="config.maxBackoffPeriod">
                            <el-input v-model="model.config.maxBackoffPeriod"></el-input>
                        </el-form-item>
                    </fieldset>
                </el-tab-pane>
            </el-tabs>
        </el-form>
    </div>
</template>

<style>
.el-form--label-left {
    .el-form-item {
        >label {
            justify-content: flex-start;
        }
    }
}

.el-tabs__content {
    height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: thin;
}

.properties-items {
    &:nth-child(2n) {
        background: #f3f3f388;
    }
}


</style>